package com.macro.mall.commission.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.macro.mall.commission.domain.OrderPredicate;
import com.macro.mall.commission.entity.OrderPredicateEntity;
import com.macro.mall.commission.event.OrderPredicateEvent;
import com.macro.mall.commission.event.OrderPredicateEventArg;
import com.macro.mall.commission.mapper.OrderPredicateMapper;
import com.macro.mall.commission.service.AssignService;
import com.macro.mall.commission.service.OrderPredicateService;
import com.macro.mall.commission.service.bo.AssignItemBo;
import com.macro.mall.commission.service.bo.InsertOrderPredicateInput;
import com.macro.mall.commission.service.bo.PagedQueryOrderPredicateInput;
import com.macro.mall.commission.service.bo.UpdateOrderPredicateInput;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.common.api.util.BigDecimalUtils;
import com.macro.mall.common.api.util.StringUtils;
import com.macro.mall.oms.entity.OrderEntity;
import com.macro.mall.oms.service.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 订单佣金预估Service
 *
 * @author xuyanjun
 * @date 2019-12-11
 */
@Slf4j
@Service
public class OrderPredicateServiceImpl extends ServiceImpl<OrderPredicateMapper, OrderPredicateEntity> implements OrderPredicateService, ApplicationEventPublisherAware {

    private ExecutorService executorService = Executors.newFixedThreadPool(1);

    @Autowired
    private OrderPredicateMapper orderPredicateMapper;

    @Autowired
    private OrderService orderService;

    @Autowired
    private AssignService assignService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 预估
     *
     * @param orderId 订单id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void predict(long orderId) {
        OrderEntity order = orderService.getById(orderId);
        Assert.notNull(order, String.format("未找到订单id为:%s的订单。", orderId));

        if (isOrderPredicted(orderId)) {
            throw new BusinessException(String.format("生活订单id:%s已经存在结算的记录，不能进行结算。", orderId));
        }

        List<AssignItemBo> assignItemBos = assignService.listAssignItem(orderId, 0);
        List<OrderPredicateEntity> settleEntities = createSettleEntities(assignItemBos);

        saveBatch(settleEntities);

        orderService.updatePredictStatus(orderId, 10);

        List<Long> predicateIds = settleEntities.stream().map(OrderPredicateEntity::getId).collect(Collectors.toList());

        OrderPredicateEventArg eventArg = new OrderPredicateEventArg();
        eventArg.setPredicateIds(predicateIds);

        OrderPredicateEvent event = new OrderPredicateEvent(this, eventArg);

        executorService.execute(() -> {
            applicationEventPublisher.publishEvent(event);
        });
    }

    /**
     * 指定的订单id是否已结算过
     *
     * @param orderId 订单id
     * @return 是否已结算过
     */
    private boolean isOrderPredicted(long orderId) {
        LambdaQueryWrapper<OrderPredicateEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OrderPredicateEntity::getOrderId, orderId);

        int count = orderPredicateMapper.selectCount(queryWrapper);
        return count > 0;
    }

    /**
     * 创建结算实体
     *
     * @param assignItemBos 分佣条目
     * @return 结算实体
     */
    @SuppressWarnings("Duplicates")
    private List<OrderPredicateEntity> createSettleEntities(List<AssignItemBo> assignItemBos) {
        List<OrderPredicateEntity> result = new ArrayList<>();

        for (AssignItemBo assignItemBo : assignItemBos) {
            OrderPredicateEntity liveOrderSettleEntity = new OrderPredicateEntity();
            liveOrderSettleEntity.setAmount(assignItemBo.getAmount())
                    .setAssignType(assignItemBo.getAssignType())
                    .setAssignTypeName(assignItemBo.getAssignTypeName())
                    .setOrderId(assignItemBo.getOrderId())
                    .setOrderNo(assignItemBo.getOrderNo())
                    .setOrderAmount(assignItemBo.getOrderAmount())
                    .setOrderPaymentTime(assignItemBo.getOrderPaymentTime())
                    .setOrderCompleteTime(assignItemBo.getOrderCompleteTime())
                    .setOrderUserId(assignItemBo.getOrderUserId())
                    .setOrderUserName(assignItemBo.getOrderUserName())
                    .setPercent(assignItemBo.getPercent())
                    .setUserId(assignItemBo.getUserId())
                    .setUserName(assignItemBo.getUserName())
                    .setRemark(assignItemBo.getRemark());

            LocalDateTime now = LocalDateTime.now();
            liveOrderSettleEntity.setCreateTime(now);
            liveOrderSettleEntity.setUpdateTime(now);

            result.add(liveOrderSettleEntity);
        }
        return result;
    }

    /**
     * 新增订单佣金预估
     *
     * @param input input
     * @return 新增id
     */
    @Override
    public long insert(InsertOrderPredicateInput input) {
        OrderPredicateEntity orderPredicateEntity = new OrderPredicateEntity();
        orderPredicateEntity.setUserId(input.getUserId())
                .setUserName(input.getUserName())
                .setOrderId(input.getOrderId())
                .setOrderNo(input.getOrderNo())
                .setOrderUserId(input.getOrderUserId())
                .setOrderUserName(input.getOrderUserName())
                .setOrderPaymentTime(input.getOrderPaymentTime())
                .setOrderCompleteTime(input.getOrderCompleteTime())
                .setOrderAmount(input.getOrderAmount())
                .setAmount(input.getAmount())
                .setPercent(input.getPercent())
                .setAssignType(input.getAssignType())
                .setAssignTypeName(input.getAssignTypeName())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        orderPredicateEntity.setCreateTime(now);
        orderPredicateEntity.setUpdateTime(now);

        orderPredicateMapper.insert(orderPredicateEntity);
        return orderPredicateEntity.getId();
    }

    /**
     * 修改订单佣金预估
     *
     * @param input input
     */
    @Override
    public void update(UpdateOrderPredicateInput input) {
        OrderPredicateEntity orderPredicateEntity = orderPredicateMapper.selectById(input.getId());
        if (orderPredicateEntity == null) {
            throw new BusinessException(String.format("未能根据Id:%s找到指定的订单佣金预估。", input.getId()));
        }

        orderPredicateEntity = new OrderPredicateEntity();
        orderPredicateEntity
                .setId(input.getId())
                .setUserId(input.getUserId())
                .setUserName(input.getUserName())
                .setOrderId(input.getOrderId())
                .setOrderNo(input.getOrderNo())
                .setOrderUserId(input.getOrderUserId())
                .setOrderUserName(input.getOrderUserName())
                .setOrderPaymentTime(input.getOrderPaymentTime())
                .setOrderCompleteTime(input.getOrderCompleteTime())
                .setOrderAmount(input.getOrderAmount())
                .setAmount(input.getAmount())
                .setPercent(input.getPercent())
                .setAssignType(input.getAssignType())
                .setAssignTypeName(input.getAssignTypeName())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        orderPredicateEntity.setUpdateTime(now);

        orderPredicateMapper.updateById(orderPredicateEntity);
    }

    @Override
    public void updateBatch(List<OrderPredicateEntity> predicateEntities) {
        updateBatchById(predicateEntities);
    }

    /**
     * 根据订单id修改已结算状态
     *
     * @param orderId 订单id
     */
    @Override
    public void updateSettledByOrderId(long orderId) {
        orderPredicateMapper.updateSettledByOrderId(orderId);
    }


    /**
     * 删除订单佣金预估
     *
     * @param id id
     */
    @Override
    public void delete(long id) {
        orderPredicateMapper.deleteById(id);
    }

    /**
     * 根据Id获取订单佣金预估
     *
     * @param id id
     * @return 订单佣金预估
     */
    @Override
    public OrderPredicateEntity getById(long id) {
        return orderPredicateMapper.selectById(id);
    }

    /**
     * 根据批量Id获取订单佣金预估
     *
     * @param batchIds 批量ids
     * @return 订单佣金预估集合
     */
    @Override
    public List<OrderPredicateEntity> listByBatchIds(List<Long> batchIds) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        return orderPredicateMapper.selectBatchIds(batchIds);
    }

    @Override
    public List<OrderPredicateEntity> listByOrderId(Long orderId) {
        LambdaQueryWrapper<OrderPredicateEntity> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(OrderPredicateEntity::getOrderId, orderId);

        return orderPredicateMapper.selectList(queryWrapper);
    }

    /**
     * 根据创建时间获取用户预估总和
     *
     * @param userId    用户id
     * @param beginTime 开始时间
     * @param endTime   结束时间
     * @return 结算总和
     */
    @Override
    public long sumAmountByCreateTimeOfUser(long userId, LocalDateTime beginTime, LocalDateTime endTime) {
        com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(userId > 0, "用户id不能为空。");
        com.baomidou.mybatisplus.core.toolkit.Assert.notNull(beginTime, "要查询的开始时间不能为空。");
        com.baomidou.mybatisplus.core.toolkit.Assert.notNull(endTime, "要查询的结束时间不能为空。");
        com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(beginTime.isBefore(endTime), "开始时间不能大于结束时间。");

        Long sumAmount = orderPredicateMapper.sumAmountByCreateTimeOfUser(userId, beginTime, endTime);
        return sumAmount == null ? 0 : sumAmount;
    }

    /**
     * 分页查询
     *
     * @param input input
     * @return 分页的订单佣金预估
     */
    @Override
    public Page<OrderPredicateEntity> pagedQuery(PagedQueryOrderPredicateInput input) {
        LambdaQueryWrapper<OrderPredicateEntity> queryWrapper = Wrappers.lambdaQuery();

        if (input.getUserId() != null) {
            queryWrapper.eq(OrderPredicateEntity::getUserId, input.getUserId());
        }
        if (input.getOrderId() != null) {
            queryWrapper.eq(OrderPredicateEntity::getOrderId, input.getOrderId());
        }
        if (input.getCreateBeginTime() != null) {
            queryWrapper.ge(OrderPredicateEntity::getCreateTime, input.getCreateBeginTime());
        }
        if (input.getCreateEndTime() != null) {
            queryWrapper.le(OrderPredicateEntity::getCreateTime, input.getCreateEndTime());
        }

        if (StringUtils.isNotBlank(input.getSortField())) {
            if (PagedQueryOrderPredicateInput.CREATE_TIME_FIELD_NAME.equalsIgnoreCase(input.getSortField())) {
                queryWrapper.orderBy(true, input.isAsc(), OrderPredicateEntity::getCreateTime);
            }
        }

        PageHelper.startPage(input.getPageIndex(), input.getPageSize());

        return (Page<OrderPredicateEntity>) orderPredicateMapper.selectList(queryWrapper);
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderPredicateEntity 实体
     * @return orderPredicate
     */
    @Override
    public OrderPredicate entityToDomain(OrderPredicateEntity orderPredicateEntity) {
        if (orderPredicateEntity == null) {
            return null;
        }

        OrderPredicate orderPredicate = new OrderPredicate();
        orderPredicate
                .setId(orderPredicateEntity.getId())
                .setCreateTime(orderPredicateEntity.getCreateTime())
                .setUpdateTime(orderPredicateEntity.getUpdateTime())
                .setUserId(orderPredicateEntity.getUserId())
                .setUserName(orderPredicateEntity.getUserName())
                .setOrderId(orderPredicateEntity.getOrderId())
                .setOrderNo(orderPredicateEntity.getOrderNo())
                .setOrderUserId(orderPredicateEntity.getOrderUserId())
                .setOrderUserName(orderPredicateEntity.getOrderUserName())
                .setOrderPaymentTime(orderPredicateEntity.getOrderPaymentTime())
                .setOrderCompleteTime(orderPredicateEntity.getOrderCompleteTime())
                .setOrderAmount(BigDecimalUtils.fromFengToYuan(orderPredicateEntity.getOrderAmount(), 2))
                .setAmount(BigDecimalUtils.fromFengToYuan(orderPredicateEntity.getAmount(), 2))
                .setPercent(orderPredicateEntity.getPercent())
                .setAssignType(orderPredicateEntity.getAssignType())
                .setAssignTypeName(orderPredicateEntity.getAssignTypeName())
                .setRemark(orderPredicateEntity.getRemark());

        return orderPredicate;
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderPredicateEntities 实体
     * @return orderPredicates
     */
    @Override
    public List<OrderPredicate> entityToDomain(List<OrderPredicateEntity> orderPredicateEntities) {
        List<OrderPredicate> result = new ArrayList<>();
        if (orderPredicateEntities == null) {
            return result;
        }

        for (OrderPredicateEntity orderPredicateEntity : orderPredicateEntities) {
            OrderPredicate orderPredicate = entityToDomain(orderPredicateEntity);
            result.add(orderPredicate);
        }
        return result;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
